from flask import *
from io import BytesIO
from baike import *
import qrcode, base64, os, ast
import time
import socket, requests
import html2text

__version__ = '0.0.1'

# ------ FUNCTION ------ #

def GetIP():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(('8.8.8.8', 80))
        ip = s.getsockname()[0]
    finally:
        s.close()
    return ip

def SimplifyPath(path):
        path.replace('\\', '/')
        path.replace('//', '/')
        list = path.split('/')
        res =[]
        for i in range(len(list)):
            if list[i] == '..' and len(res) > 0:
                res = res[:-1]
            elif list[i] != '' and list[i] != '.' and list[i] != '..':
                res.append(list[i])
        return '/'.join(res)

def ConvertSize(text):
    units = ["B", "KiB", "MiB", "GiB", "TiB", "PiB"]
    size = 1024
    for i in range(len(units)):
        if (text/ size) < 1:
            return "%.1f%s" % (text, units[i])
        text = text/ size

def LoadConfig():
    path = os.path.dirname(os.path.realpath(__file__))
    dataf = os.path.join(path, 'data', 'Accept.cot')
    with open(dataf, 'r', encoding='utf-8') as df:
        try:
            config = ast.literal_eval(df.read())
        except:
            raise ImportError('File \'Accept.cot\' is incomplete.')
    # Base_dir
    base_dir = config.get('base_dir', './data/pth/')
    if base_dir[0] != '.':
        pass
    else:
        base_dir = os.path.join(path, SimplifyPath(base_dir))
    conf = {
        'base_dir':os.path.abspath(base_dir)
    }
    # More_dir
    more_dir = config.get('more_dir', {})
    more_list = {}
    for p in more_dir:
        v = more_dir[p]
        if v[0] != '.':
            pass
        else:
            v = os.path.abspath(os.path.join(path, SimplifyPath(v)))
        more_list[p] = v
    conf['more_dir'] = more_list
    # Account
    conf['account'] = config.get('account', {})
    print(conf)
    return conf

def SaveConfig(conf):
    path = os.path.dirname(os.path.realpath(__file__))
    dataf = os.path.join(path, 'data', 'Accept.cot')
    with open(dataf, 'w', encoding='utf-8') as df:
        df.write(str(conf))

def CreatIndex(req_path, now_branch):
    req_path = os.path.abspath(req_path)
    now_level = req_path.replace(os.path.abspath(now_branch), '/mirror/')
    names = [name for name in os.listdir(req_path)
            if os.path.isfile(os.path.join(req_path, name))]
    names_list = []
    for f in names:
        p = os.path.join(req_path, f)
        size = ConvertSize(os.path.getsize(p))
        last_time = time.strftime("%Y-%m-%d %H:%M", time.localtime(os.path.getmtime(p)))
        names_list.append([f, size, last_time, os.path.join(now_level, f)])
    # Get all dirs
    dirnames = [name for name in os.listdir(req_path)
        if os.path.isdir(os.path.join(req_path, name))]
    dirs_list = []
    for d in dirnames:
        last_time = time.strftime("%Y-%m-%d %H:%M", time.localtime(os.path.getmtime(os.path.join(req_path, d))))
        dirs_list.append([d+'/', os.path.join(now_level, d), last_time])
    
    return names_list, dirs_list

class BingImg:
    def __init__(self):
        self.update()

    def update(self):
        self.cont = requests.get("https://api.xygeng.cn/Bing/").content
        self.date = time.strftime("%Y-%m-%d", time.localtime())
    
    def get(self):
        date = time.strftime("%Y-%m-%d", time.localtime())
        if date == self.date:
            return self.cont
        else:
            self.update()
            return self.cont

# ------ INIT ------ #

conf = LoadConfig()
bingp = BingImg()
localip = GetIP()
print(localip)
app = Flask(__name__)
app.secret_key = 'C-i7tyW8~gmckBS'
app.config.update(DEBUG=True)

# ------ PAGE ------ #

def Account(session):
    data = {
        'account':{
            'uid':None,
            'head':None,
        },
    }
    if session.get('uid') and session.get('uid') != '_None':
        data['account']['uid'] = session.get('uid')
        data['account']['head'] = '3206921401'
    
    data['ip'] = localip
    
    return data
    
@app.route('/')
def home():
    data = Account(session)
    return render_template('home.html', data=data)

@app.route('/uidadd')
def uidadd():
    session['uid'] = '001'
    return redirect('/')

# ----- Search on Baidu ----- #

@app.route('/search/')
@app.route('/search')
def Search_Baidu():
    data = Account(session)
    key = request.values.get('s', '')
    data['key'] = key
    return render_template('search.html', data=data)

# ----- File Download ----- #

@app.route('/mirror/')
@app.route('/mirror')
def index():
    data = Account(session)
    # cookies
    branch = request.cookies.get("index_branch")
    return_list = ['Home']
    for i in conf['more_dir']:
        return_list.append(i)
    if branch == 'Home':
        now_branch = conf['base_dir']
    elif branch == None:
        now_branch = None
    else:
        now_branch = conf['more_dir'].get(branch, None)
        return_list.remove(branch)
        return_list.insert(0, branch)
    if not now_branch:
        response = make_response(redirect('/mirror'))
        response.set_cookie('index_branch', 'Home')
        return response
    # Get all dirs
    dirnames = [name for name in os.listdir(now_branch)
        if os.path.isdir(os.path.join(now_branch, name))]
    dirs_list = []
    for d in dirnames:
        last_time = time.strftime("%Y-%m-%d %H:%M", time.localtime(os.path.getmtime(os.path.join(now_branch, d))))
        dirs_list.append([d, os.path.join('/mirror', d), last_time])
    data['dirs'] = dirs_list
    data['branch'] = return_list
    return render_template('index/mirror.html', data=data)

@app.route('/mirror/<path:info>/')
@app.route('/mirror/<path:info>')
def index_file(info):
    data = Account(session)
    # cookies
    branch = request.cookies.get("index_branch", 'Home')
    if branch == 'Home':
        now_branch = conf['base_dir']
    else:
        now_branch = conf['more_dir'].get(branch, None)
    if not now_branch:
        response = make_response(redirect('/mirror'))
        response.set_cookie('index_branch', 'Home')
        return response
    # init path
    req_path = os.path.abspath(os.path.join(now_branch, info))
    parent_path = os.path.abspath(os.path.join(req_path, os.path.pardir))
    up_level = parent_path.replace(now_branch, '/mirror/').replace('\\', '/')
    if not os.path.exists(req_path):
        return redirect(up_level)
    if os.path.isfile(req_path):
        directory, filename =  os.path.split(req_path)
        response = make_response(send_from_directory(directory, filename, as_attachment=True))
        response.headers["Content-Disposition"] = "attachment; filename={}".format(filename.encode().decode('latin-1'))
        return response
    now_level = req_path.replace(os.path.abspath(now_branch), '/mirror/').replace('\\', '/')
    try:
        names_list, dirs_list = CreatIndex(req_path, now_branch)
    except:
        response = make_response(redirect(up_level))
        response.set_cookie('Error', 'Limited Access!')
        return response
    # return
    data['up_level'] = up_level
    data['now_level'] = now_level.replace('/mirror', '')
    data['files'] = names_list
    data['dirs'] = dirs_list
    return render_template('index/index.html', data=data)

# ----- Online Exam ----- #

@app.route('/exam/')
@app.route('/exam')
def exam_home():
    data = Account(session)
    return render_template('exam/home.html', data=data)

@app.route('/exam/test/')
@app.route('/exam/test')
def exam_test():
    return render_template('exam/test.html')

@app.route('/exam/paper/')
@app.route('/exam/paper')
def exam_paper():
    return render_template('exam/paper.html')

# ----- Doc By Markdown ----- #

@app.route('/doc/')
@app.route('/doc/')
def doc_home():
    data = Account(session)
    return render_template('doc/home.html', data=data)

@app.route('/doc/<nid>/')
@app.route('/doc/<nid>')
def doc_show(nid):
    data = Account(session)
    path = os.path.dirname(os.path.realpath(__file__))
    dataf = os.path.join(path, 'data', 'doc')
    if (nid+'.md') in os.listdir(dataf):
        data['nid'] = nid
        with open(os.path.join(dataf, nid+'.md'), 'r', encoding='utf-8') as f:
            text = f.read(6)
            if text == 'TOURL:':
                data['nid'] = f.read()
        return render_template('doc/show.html', data=data)
    return redirect('/doc')

# ----- Online Info By QRCode ----- #

@app.route('/qc/<code>/')
@app.route('/qc/<code>')
def info_code(code):
    data = Account(session)
    data['code'] = code
    return render_template('coner/coner.html', data=data)

# ------ API ------ #

@app.route('/api/account/', methods=['GET', 'POST',])
@app.route('/api/account', methods=['GET', 'POST',])
def set_account():
    session['uid'] = 'A03'
    return redirect('/')


@app.route('/api/todown/', methods=['GET'])
@app.route('/api/todown', methods=['GET'])
@app.route('/api/todown/<path:info>/', methods=['GET'])
@app.route('/api/todown/<path:info>', methods=['GET'])
def html_md(info=None):
    if info:
        key = info
    else:
        key = request.values.get('tar', '')
    p = Page(key)
    maker = html2text.HTML2Text()
    article = maker.handle(p.http.text)
    return article


@app.route('/api/down/', methods=['GET'])
@app.route('/api/down', methods=['GET'])
@app.route('/api/down/<path:info>/', methods=['GET'])
@app.route('/api/down/<path:info>', methods=['GET'])
def markdown(info=None):
    path = os.path.dirname(os.path.realpath(__file__))
    dataf = os.path.join(path, 'data', 'doc')
    if info:
        nid = info
    else:
        nid = request.values.get('nid')
    if (len(nid) >= 12) and (nid[0:4] == 'http'):
        text = requests.get(nid).text
        return text
    if (len(nid) >= 12) and (nid[0:6] == 'p-http'):
        content = requests.get(nid[2:]).content
        return content
    if (nid == 'bingp'):
        return bingp.get()
    if (nid+'.md') in os.listdir(dataf):
        with open(os.path.join(dataf, nid+'.md'), 'r', encoding='utf-8') as f:
            text = f.read()
        return text
    return ''

@app.route('/api/qrcode/', methods=['GET', 'POST'])
@app.route('/api/qrcode', methods=['GET', 'POST'])
@app.route('/api/qrcode/<path:info>/', methods=['GET', 'POST'])
@app.route('/api/qrcode/<path:info>', methods=['GET', 'POST'])
def QRcode(info=None):
    if not info:
        if request.method == 'POST':
            data = str(request.form.get('data', 'None'))
        else:
            data = str(request.args.get('data', 'None'))
    else:
        data = info
    
    if data == '':data = 'None'

    qr = qrcode.QRCode(
        error_correction=qrcode.constants.ERROR_CORRECT_H,
        box_size=10,
        border=1,
    )
    data = data.encode('utf-8')
    qr.add_data(data)
    img = qr.make(fit=True)
    out = BytesIO()
    img = qr.make_image(fill_color="black", back_color="white")
    img.save(out, 'PNG')
    return u"data:image/png;base64," + base64.b64encode(out.getvalue()).decode('ascii')

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=80)
